/*
 * NodeImpl.h
 *
 *  Created on: Apr 19, 2009
 *      Author: wrice
 */

#ifndef NODEIMPL_H_
#define NODEIMPL_H_
#include "DOMCoreImp.h"
namespace DOMCoreImp {

class NodeImp : IMPLEMENTS( Node ), IMPLEMENTS( EventTarget ), IMPLEMENTS( DocumentEvent ) {
protected:
	friend class DocumentImp;
	NodeImp(DOMString nodeName, DocumentImp * ownerDocument);

public:
	// name
	virtual DOMString getNodeName();

	// value
	virtual DOMString getNodeValue() throw(DOMExceptionPtr);
	virtual void setNodeValue(DOMString) throw(DOMExceptionPtr);

	// owner
	virtual Document * getOwnerDocument();

	// attribute
	virtual bool hasAttributes();
	virtual NamedAttrMap * getAttributes();

	// parent
	virtual Node * getParentNode();

	// child
	virtual bool hasChildNodes();
	virtual NodeList * getChildNodes();
	virtual Node * getFirstChild();
	virtual Node * getLastChild();
	virtual Node * getPreviousSibling();
	virtual Node * getNextSibling();
	virtual Node * insertBefore( Node * newChild, Node * refChild ) throw(DOMExceptionPtr);
	virtual Node * replaceChild( Node * newChild, Node * oldChild ) throw (DOMExceptionPtr);
	virtual Node * removeChild( Node * oldChild) throw(DOMExceptionPtr);
	virtual Node * appendChild( Node * newChild) throw(DOMExceptionPtr);

	// events target
	virtual void addEventListener(DOMString type, EventListener * listener, bool useCapture);
	virtual void removeEventListener(DOMString type, EventListener * listener, bool useCapture);
	virtual bool dispatchEvent(Event * evt) throw(EventExceptionPtr);

	// document event
	virtual Event * createEvent(DOMString eventType) throw(DOMExceptionPtr);


public: // new methods
	virtual DocumentImp * getOwnerDocumentImp();
	virtual void setParentNode( NodeImp * parent );
	static unsigned long getMyIndexOnParent(Node * node) throw(DOMExceptionPtr);
	static void setNullAsParentNodeOf( Node * node );

private:
	const DOMString nodeName_; // for all
	DOMString nodeValue_;
	NodeListImpPtr childNodes_;

	NodeImp * parentNode_;
	DocumentImp * ownerDocument_;

	bool hasParentNode();
	bool hasChildNode( Node * refChild );
	void setMyselfAsParentNodeOf( Node * newChild );
	bool isNodeInTheSameDocument( Node * aNode );

	struct Imp;

private: // for EventTarget
	typedef Tuple< LOKI_TYPELIST_2( DOMString, EventListener * )> Type_EventListener;
	enum { TypeNameE, EventListenerE };

	class Comparator {
	public:
		inline bool operator()(const Type_EventListener & lhs, const Type_EventListener & rhs) const {
			return Field< TypeNameE >( lhs ) < Field< TypeNameE >( rhs )
				|| Field< EventListenerE >( lhs ) < Field< EventListenerE >( rhs );
		}
	};

private: // for EventTarget
	typedef set< Type_EventListener, Comparator > EventListeners;
	typedef EventListeners::const_iterator EventListenersIterator;
	typedef EventListeners::iterator EventListenersModifiableIterator;
	EventListeners eventListenersForMyself_;
	EventListeners eventListenersForCapturing_;
	EventListeners & getContainer(bool useCapture);
};

}

#endif /* NODEIMPL_H_ */
